using System;
using Kaleida.ServiceMonitor.Framework;
using Kaleida.ServiceMonitor.Framework.Responses;

namespace Kaleida.ServiceMonitor.Operations.ResponseHandlers
{
    public class MustEqual : ResponseHandler
    {
        private readonly string expected;

        public MustEqual(string expected)
        {
            this.expected = expected;
        }

        public override string Description
        {
            get { return string.Format("expect equal to '{0}'", expected); }
        }

        public override string ProcessResponse(object response)
        {
            if (response is int && expected.IsInteger())
            {
                var actualInt = (int)response;
                TestAsInteger(actualInt);
                return actualInt.ToFormattedString();
            }
            if (response is decimal && expected.IsDecimal())
            {
                var actualDecimal = (decimal)response;
                TestAsDecimal(actualDecimal);
                return actualDecimal.ToFormattedString();
            }
            if (response is TimeSpan && expected.IsTimeSpan())
            {
                var actualTimespan = (TimeSpan)response;
                TestAsTimespan(actualTimespan);
                return actualTimespan.ToFormattedString();
            }
            if (response is ITimedEvent && expected.IsTimeSpan())
            {
                var actualTimespan = ((ITimedEvent)response).TimeTaken;
                TestAsTimespan(actualTimespan);
                return "Time Taken " + actualTimespan.ToFormattedString();
            }
            if (response is IStringContainer)
            {
                var actualContent = ((IStringContainer)response).Content;
                TestAsString(actualContent);
                return actualContent.ToFormattedString();
            }
            
            var actualString = response.ToString();
            TestAsString(actualString);
            return actualString.ToFormattedString();
        }

        private void TestAsString(string actualString)
        {
            if (actualString != expected)
                throw NewMismatchException(expected.ToFormattedString(), actualString.ToFormattedString());
        }

        private void TestAsInteger(int actualInt)
        {
            var expectedInt = Convert.ToInt32(expected);

            if (actualInt != expectedInt)
                throw NewMismatchException(expectedInt.ToFormattedString(), actualInt.ToFormattedString());
        }

        private void TestAsDecimal(decimal actualDecimal)
        {
            var expectedDecimal = Convert.ToDecimal(expected);

            if (actualDecimal != expectedDecimal)
                throw NewMismatchException(expectedDecimal.ToFormattedString(), actualDecimal.ToFormattedString());
        }

        private void TestAsTimespan(TimeSpan actualTimespan)
        {
            var expectedTimespan = expected.ToTimeSpan();

            if (actualTimespan != expectedTimespan)
                throw NewMismatchException(expectedTimespan.ToFormattedString(), actualTimespan.ToFormattedString());
        }

        private static InvalidOperationException NewMismatchException(object expected, object response)
        {
            return new InvalidOperationException(string.Format("Expected response to equal {0} but was {1}", expected, response));
        }
    }
}